#include "graphics.h"

graphics::graphics(int width, int height, int bpp) {
    screenWidth = width;                                                                   // Setting Variables
    screenHeight = height;
    screenBBP = bpp;

    capFrames = true;

    frame = 0;
    frameCap = 60;

    initSDL();
    initGL();
    resizeWindow(screenWidth, screenHeight);
}

bool graphics::initSDL() {
    SDL_Init(SDL_INIT_VIDEO);                                                               // Init SDL Video
    videoInfo = SDL_GetVideoInfo();

    /* the flags to pass to SDL_SetVideoMode */
    videoFlags  = SDL_OPENGL;                       /* Enable OpenGL in SDL */
    videoFlags |= SDL_GL_DOUBLEBUFFER;              /* Enable double buffering */
    videoFlags |= SDL_HWPALETTE;                    /* Store the palette in hardware */
    videoFlags |= SDL_RESIZABLE;                    /* Enable window resizing */

    /* This checks to see if surfaces can be stored in memory */
    if(videoInfo->hw_available) {
        videoFlags |= SDL_HWSURFACE;
    } else {
        videoFlags |= SDL_SWSURFACE;
    }

    if (videoInfo->blit_hw)
        videoFlags |= SDL_HWACCEL;

    SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
//    SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8 );
//    SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8 );
//    SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,8 );
//    SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32 );
//    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);

    screen = SDL_SetVideoMode( screenWidth, screenHeight, screenBBP, videoFlags);           // Set Video Mode
    SDL_WM_SetCaption( "Infiniminer++", NULL );                                             // Set Title of Window

    return true;
}

bool graphics::initGL() {
    /* Enable smooth shading */
    glShadeModel( GL_SMOOTH );

    /* Set the background black */
    glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );

    /* Depth buffer setup */
    glClearDepth( 1.0f );

    /* Enables Depth Testing */
    glEnable( GL_DEPTH_TEST );

    /* Enables Backface Culling */
    glEnable(GL_CULL_FACE);

    /* The Type Of Depth Test To Do */
    glDepthFunc( GL_LEQUAL );

    /* Really Nice Perspective Calculations */
    glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );

    return true;
}

bool graphics::resizeWindow(int width, int height) {
    /* Height / width ration */
    GLfloat ratio;

    /* Protect against a divide by zero */
    if ( height == 0 )
        height = 1;

    ratio = ( GLfloat )width / ( GLfloat )height;

    /* Setup our viewport. */
    glViewport( 0, 0, ( GLint )width, ( GLint )height );

    /* change to the projection matrix and set our viewing volume. */
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity( );

    /* Set our perspective */
    gluPerspective( 45.0f, ratio, 0.1f, 500.0f );

    /* Make sure we're chaning the model view and not the projection */
    glMatrixMode( GL_MODELVIEW );

    /* Reset The View */
    glLoadIdentity( );

    return true;
}

void graphics::resetScene() {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);                                     // Clear The Screen And The Depth Buffer
    glLoadIdentity();                                                                                               // Reset The Current Modelview Matrix
}

void graphics::drawScene() {
        start();
        resetScene();

        rotateScene();
        translateScene();

        for(int i=0; i < currentMapSize(); i++) {
            for(int j=0; j < currentMapSize(); j++) {
                for(int k=0; k < currentMapSize(); k++) {
                    if(currentMap()[i][j][k].type == 1) {
                        drawCube(i, j, k);
                    }
                }
            }
        }

        // Update screen
        SDL_GL_SwapBuffers();
        frame++;

        // Limit FPS
        limitFPS();
}

void graphics::translateScene() {
    GLfloat xtrans = -currentPosition().x;                                                                  // Used For Player Translation On The X Axis
    GLfloat ztrans = -currentPosition().z;                                                                  // Used For Player Translation On The Z Axis
    GLfloat ytrans = -currentPosition().y;
    glTranslatef(xtrans, ytrans, ztrans);
}

void graphics::rotateScene() {
    GLfloat pitch = currentOrientation().pitch;
    GLfloat yaw = currentOrientation().yaw;
    glRotatef(pitch, 1.0, 0.0, 0.0);                           //rotate our camera on the x-axis (left and right)
    glRotatef(yaw, 0.0, 1.0, 0.0);                         //rotate our camera on the y-axis (up and down)
}

void graphics::limitFPS() {
    if(capFrames && getTicks() < 1000 / frameCap) {
        SDL_Delay((1000 / frameCap) - getTicks());
    }
}

int graphics::currentFrame() {
    return frame;
}